﻿using System;
using System.IO;
using System.Threading;
using System.Collections;
using System.Collections.Generic;

using SBPweb.Forge.Common.Patterns;

using SBPweb.Forge.Logger.Writers;

namespace SBPweb.Forge.Logger.Actors
{

    public class LogListener
    {

        #region Private fields

        private LockHelper lh = new LockHelper("LoggerThread");
        private AutoResetEvent are = new AutoResetEvent(false);
        private LogWriter writer;
        private bool canStop;
        private Queue<LogItem> itemQueue = new Queue<LogItem>();

        #endregion

        #region Constructor logic

        public LogListener(LogWriter writer)
        {
            this.writer = writer;
        }

        internal LogListener(Configuration.ListenerElement element)
        {
            Type type = Type.GetType(element.Writer.Type);
            if (type == null)
            {
                throw new TypeLoadException(string.Format("Type of {1} could not be found for listener element {0}!", element.Name, element.Writer.Type));
            }
            this.writer = (LogWriter)Activator.CreateInstance(type, element.Writer.Settings);
        }

        #endregion

        #region Methods

        internal void StartWriting()
        {
            try
            {
                if (writer == null)
                {
                    throw new ArgumentNullException("writer as LogWriter");
                }

                while (!canStop)
                {
                    are.WaitOne();
                    using (lh.GetLock())
                    {
                        LogItem item = null;
                        do
                        {
                            if (itemQueue.Count > 0)
                            {
                                item = itemQueue.Dequeue();
                                writer.Write(item);
                            }
                            else
                            {
                                item = null;
                            }
                        }
                        while (item != null);
                    }
                }
            }
            catch (IOException ex)
            {
                writer.Flush();
            }
            finally
            {
                writer.Close();
            }
        }

        internal void EndWriting()
        {
            using (lh.GetLock())
            {
                canStop = true;
                are.Set();
            }
        }

        public void EnqueueItem(LogItem item)
        {
            using (lh.GetLock())
            {
                itemQueue.Enqueue(item);
            }
            //TODO: do resetevent handling based on flush policy
            are.Set();
        }

        #endregion

    }

}